grammar Txt2tags ;

options 
{
  language=Java;
	k = 5 ;
	output = AST;
	//filter = true ;
	//caseSensitive = false ;
}

@header {
    package agh.tk.markuptranslation;
}
@lexer::header {package agh.tk.markuptranslation;}

start :
  txt2tagsFile ;
  
txt2tagsFile returns [DataModel  value]:
	node1=txt2tagsMarkupSection node2=txt2tagsFile
		{
		  $value = new DataModel((IComponent)$node1.value, (IComponent)$node2.value) ;
		}
	| node3=textBlock node4=txt2tagsFile
		{ 
			$value = new DataModel(new Text($node3.text, null), (IComponent)$node4.value) ; 
		}
	| n=newLine node5=txt2tagsFile
		{ 
			$value = new DataModel((IComponent)$n.value, (IComponent)$node5.value) ; 
		}
	| ()
		{ 
		  $value = null ; 
		} ;
		
txt2tagsMarkupSection returns [IComponent value] :
	node1=comment 
	 {
    $value = $node1.value ; //node.value ;
   } 
	| node2=list
	 {
    $value = $node2.value ; //node.value ;
    }  
	| node3=title
	  {
    $value = $node3.value ; //node.value ;
    }  
	| node4=orderedTitle
	  {
    $value = $node4.value ; //node.value ;
    }  
	| node5=boldText
	  {
    $value = $node5.value ; //node.value ;
    }  
	| node6=underlineText
	  {
    $value = $node6.value ; //node.value ;
    }  
	| node7=italicText
	  {
    $value = $node7.value ; //node.value ;
    }  
	| node8=deletedText
	  {
    $value = $node8.value ; //node.value ;
    }  
	| node9=monospacedText
	  {
    $value = $node9.value ; //node.value ;
    } 
  | node10=quote
    {
      $value= $node10.value ;
    }
  | node11=verbatimLine
    {
      $value =$node11.value ;
    }
  | node12=verbatimArea
    {
      $value = $node12.value ;
    } 
  | node13=rowArea
  {
    $value = $node13.value ;
  }
  | node14=taggedArea 
  {
    $value = $node14.value ;
  }
  | node15=table
  {
    $value = $node15.value ;
  }
  | node16=link
  {
    $value = $node16.value ;
  }
  | node17=separtor
  {
    $value = $node17.value ;
  };
  

separtor returns [Separator value] :
  SEPARATOR
  {
    $value = new Separator(SeparatorType.NORMAL) ;
  }
  | STRONGSEPARATOR
  {
    $value = new Separator(SeparatorType.STRONG) ;
  } ;
  
link returns [IComponent value] :
  (LINKSYMBOL
  (
    (LINKSYMBOL l1=line LINKSYMBOLC l=line)
    {
      $value = new Link(new Text($l.text, null), new Image(new Text($l1.text, null), null)) ;
    }
    | (l=line (a=ADDRESS)?)
    {
      if($a == null)
        $value = new Image(new Text($l.text, null), null) ;
      else
        $value = new Link(new Text($a.text, null), new Text($l.text, null)) ;
    }
  )
  LINKSYMBOLC) 
  | a=ADDRESS
  {
    $value = new Link(new Text($a.text, null), null) ;
  }
  | m=MAIL
  {
    $value = new Mail(new Text($m.text, null), null) ;
  };
  

table returns [Table value] :
  TABLEHEADER header=tableHeader rows=tableRows
  {
    $value = new Table($header.value, $rows.value) ;
  }
  ;

tableHeader returns [TableHeader value] :
  l=line TABLECELL t=tableHeader
  {
    $value = new TableHeader(new Text($l.text, null), t.value) ;
  }
  | newLine 
  {
    $value = null ;
  };

tableRows returns [Table value] :
  (TABLECELL row=tableRow rows=tableRows)
  {
    $value = new Table($row.value, $rows.value) ;
  }
  |() ;
  
tableRow returns [TableRow value] :
  l=line TABLECELL r=tableRow
  {
    $value = new TableRow(new Text($l.text, null), $r.value) ;
  }
  | newLine
  {
    $value = null ;
  } ;

taggedArea returns [HTMLSection value] :
  TAGGEDAREA a=allWithoutTaggedArea TAGGEDAREA 
  {
    $value = new HTMLSection($a.text) ;
  };
 
allWithoutTaggedArea :
  (~TAGGEDAREA)* ;  

rowArea returns [NoWikiBlock value] :
  RAWAREA a=allWithoutRawArea RAWAREA 
  {
    $value = new NoWikiBlock($a.text.replaceAll("\\s+", " ")) ;
  };
  
allWithoutRawArea :
  (~RAWAREA)* ;
  
verbatimArea returns [CodeBlock value] :
  VERBATIMAREA a=allWithoutVerbatimArea VERBATIMAREA
  {
    $value= new CodeBlock($a.text) ;
  };

allWithoutVerbatimArea :
  (~VERBATIMAREA)* ;   
  
verbatimLine returns [Text value] :
  VERBATIMLINE l=allWithoutNewLine newLine
  {
    $value = new Text($l.text, TextFormatting.VERBATIMLINE) ;
  } ;

quote returns [IComponent value] :
  quoteSymbol=QUOTE t=line (q=quote | n=newLine)
  {
    int level = $quoteSymbol.text.length() - 1;
    if(n != null)
      $value = new Quote($t.text, level) ;
    else
    {
      if(q.value instanceof Quote)
      {
        Quote prevQuote = (Quote)(q.value) ;
        int qLevel = prevQuote.getPersonNumber() ;
        if(qLevel == level)
          $value = new Quote($t.text + " " + prevQuote.getText(), level) ;
        else
          $value = new DataModel(new Quote($t.text, level), prevQuote) ;
      }
      if(q.value instanceof DataModel)
      {
        Quote prevQuote= (Quote)((AbstractComponent)(q.value)).getLeftChild() ;
        IComponent right = ((AbstractComponent)(q.value)).getRightChild() ;
        int qLevel = prevQuote.getPersonNumber() ;
        if(qLevel == level)
          $value = new DataModel(new Quote($t.text + " " + prevQuote.getText(), level), right) ;
        else
          $value = new DataModel(new Quote($t.text, level), q.value) ;
      }
    }
  } ;  
  
list returns [IComponent value]:
	node1=orderedList
	{
   $value = $node1.value ; 
  } 
	| node3=unorderedList
	{
   $value = $node3.value ;
  } 
	| node2=definitionList
	{
   $value = $node2.value ;
  }
	;
	
orderedList returns [OrderedList value] :
	ol=ORDEREDLIST l=listItem (NEWLINE | o=orderedList)
	{
	  IComponent currentItem = null ;
	  if(!$l.text.equals("") && $l.text != null)
	    currentItem = new Text($l.text, null) ;
    $value = new OrderedList(currentItem, $o.value) ;
		int level = $ol.text.length() / 2 ;
		((AbstractWikiList)$value).setLevel(level) ;
	} ;
	
listItem :
  (textBlock)* ;

unorderedList returns [UnorderedList value] :
	l=UNORDEREDLIST li=listItem ((NEWLINE (NEWLINE | u1=unorderedList)) | u2=unorderedList)
	{
	  IComponent nextListItem = null ;
	  if(u1 != null)
	   nextListItem = u1.value ;
	  if(u2 != null)
	   nextListItem = u2.value ;
	  IComponent text = new Text($li.text, null) ;
	  
		$value = new UnorderedList(text, nextListItem) ;
		int level = $l.getText().length() / 2 ;
		((AbstractWikiList)$value).setLevel(level) ;
	} ;

definitionList returns [IComponent value] :
	l=DEFINITIONLIST (NEWLINE | (l1=line NEWLINE l2=line d=definitionList))
	{
    if(l1 == null)
      $value = null ;
    else
    {
      Definition definition = new Definition($l1.text, $l2.text) ;
      $value = new DefinitionList(definition, $d.value) ;
    }
	} ;

insideBoldText returns [Text value] :
  i=italicText in=insideBoldText 
  {
    $value = new Text($i.value, $in.value, null) ;
  }
  | u=underlineText in2=insideBoldText
  {
    $value = new Text($u.value, $in2.value, null) ;
  }
  | l=line in3=insideBoldText
  {
    $value = new Text(new Text($line.text, null), $in3.value, null) ;
  }
  | NEWLINE in4=insideBoldText
  {
    $value = new Text(new Text("\n", null), $in4.value, null) ;
  }
  | ()
  {
    $value = null ;
  };
  
boldText returns [Text value] :
  BOLDSYMBOL i=insideBoldText BOLDSYMBOL 
    {
      $i.value.setTextFormatting(TextFormatting.BOLD) ;
     $value = $i.value ;
    };
    
insideItalicText returns [Text value] :
  b=boldText i1=insideItalicText
  {
    $value = new Text($b.value, $i1.value, null) ;
  }
  | u=underlineText i2=insideItalicText
  {
    $value = new Text($u.value, $i2.value, null) ;
  }
  | l=line i3=insideItalicText
  {
    $value = new Text(new Text($l.text, null), $i3.value, null) ;
  }
 | NEWLINE in4=insideItalicText
  {
    $value = new Text(new Text("\n", null), $in4.value, null) ;
  }
  | ()
  {
    $value = null ;
  } ;
    
italicText returns [Text value] :
  ITALICSYMBOL i=insideItalicText ITALICSYMBOL 
    { 
      $i.value.setTextFormatting(TextFormatting.ITALIC) ;
      $value = $i.value ;
    };
    
insideUnderlineText returns [Text value] :
  b=boldText i1=insideUnderlineText
  {
    $value = new Text($b.value, $i1.value, null) ;
  }
  | i=italicText i2=insideUnderlineText
  {
    $value = new Text($i.value, $i2.value, null) ;
  }
  | l=line i3=insideUnderlineText
  {
    $value = new Text(new Text($l.text, null), $i3.value, null) ;
  }
 | NEWLINE in4=insideUnderlineText
  {
    $value = new Text(new Text("\n", null), $in4.value, null) ;
  }
  | ()
  {
    $value = null ;
  } ;
  
underlineText returns [Text value] :
  UNDERLINESYMBOL i=insideUnderlineText UNDERLINESYMBOL
    {
      $i.value.setTextFormatting(TextFormatting.UNDERLINE) ;
      $value = $i.value ; 
    };

deletedText returns [Text value] :
	STRIKESYMBOL node=text STRIKESYMBOL
	{
		$value = new Text($node.value.toString(), TextFormatting.DELETED) ;	
	};
	
monospacedText returns [Text value]:
	MONOSPACESYDMBOL node=text MONOSPACESYDMBOL
	{
		$value = new Text($node.value.toString(), TextFormatting.MONOSPACED)  ;
	};
	
comment returns [Text value] :
	COMMENT t=textLine
	{
	  String lineText = $t.value.toString().substring(0, $t.value.toString().length() - 2) ;
		$value = new Text(lineText, TextFormatting.COMMENT) ;
	} ;
	
newLine returns [Text value] :
	n=NEWLINE
	{
    int column = $n.getCharPositionInLine() ;
    if(column == 0)    	
      $value = new Text("\n", null) ;	
    else
      $value = new Text(" ", null) ;
  } ;

text returns [Text value] :
	t1=textBlock t2=text 
		{ 
			String t2Text = "" ;
			if($t2.value != null)
				t2Text = $t2.value.toString() ;
			$value = new Text($t1.text + t2Text, null) ;
		}  
	| n=newLine t=text
		{
			String tText = "" ;
			if($t.value != null)
				tText = $t.value.toString() ;
		 	$value = new Text($n.value.toString() + tText, null) ;
		}  
	| ()
		{
			 $value = null ; 
		} ;

title returns [Headline value]:
	t=TITLESYMBOL node=text TITLESYMBOL 
	{ //DO SPRAWDZENIA
		$value = new Headline($node.value.toString(), $t.text.length()) ; 
	};

orderedTitle returns [Headline value] :
	t=ORDEREDTITLESYMBOL node=text ORDEREDTITLESYMBOL 
	{
		$value = new Headline($node.value.toString(), $t.text.length()) ; 
		((Headline)$value).setOrdered() ;
	};
	
textBlock :
	(WHITESPACE | WORD | NUMBER  | PUNCTUATIONMARK); 

textLine returns [Text value]: 
	(t1=textBlock t2=textLine)
	{
		String t2Text = "" ;
		if($t2.value != null)
			t2Text = $t2.value.toString() ;
		$value = new Text($t1.text + t2Text, null) ;
	}
	| n=newLine
	{
		$value = new Text($n.text, null) ;
	} ;

line :
  (textBlock)+ ;

allWithoutNewLine :
  (~NEWLINE)* ;


//Lexer
ITALICSYMBOL :
  '//' ;

BOLDSYMBOL :
  '**' ;
  
UNDERLINESYMBOL :
  '__' ;
  
STRIKESYMBOL_OR_SEPARATOR :
  ('-')+
  {
    if($text.length() == 2)
      $type = STRIKESYMBOL ;
    else if($text.length() < 20)
      $type = PUNCTUATIONMARK ;
    else
      $type = SEPARATOR ;
  } ;

fragment STRIKESYMBOL :
  '--' ;

fragment SEPARATOR :
  ('-')+ ;

TABLEHEADER :
  '||' ;

TABLECELL :
  '|' ;

VERBATIMAREA_OR_MONOSPACEDSYMBOL :
  ('`')+
  {
    if($text.length() == 3)
      $type = VERBATIMAREA ;
    else if($text.length() == 2)
      $type = MONOSPACESYDMBOL ;
    else
      $type = PUNCTUATIONMARK ;
  } ; 

TITLESYMBOL_SEPARATORLINE :
  ('=')+ 
  {
    if($text.length() < 4)
      $type = TITLESYMBOL ;
    else if($text.length() < 20)
      $type = PUNCTUATIONMARK ;
    else
      $type = STRONGSEPARATOR ;
  };

fragment TITLESYMBOL :
  ('=')+ ;

fragment STRONGSEPARATOR :
  ('=')+ ;   

ORDEREDTITLESYMBOL :
  ('+')+ ;

RAWAREA :
  '"""' ;

TAGGEDAREA :
  '\'\'\'' ;

ADDRESS :
  ('www.' | 'http://') WORD ('.' WORD)+ ('/' (LETTER | DIGIT | PUNCTUATIONMARK)+)? ;

NUMBER :
  (DIGIT)+ ;

WORD :
  (LETTER | DIGIT)+ ;

fragment MAIL :
  WORD ('.' WORD)* '@' WORD ('.' WORD)+  ;
  
LINKSYMBOL :
  '[' ;

LINKSYMBOLC :
  ']' ;
  
PUNCTUATIONMARK :
  '>' | '`' | '|' | ']' | '\\' | '[' |'$' | '_' | '%' | '(' | ')' | ',' | '?' | ';' | '!' | '"' | '-' | '/' | ':' | '='  | '.' | '#' | '<' | '@' | '\'' | '*' | '{' ;

LIST_OR_COMMENT_OR_NEWLINE_OR_VERBATIM_OR_NEWLINE :
  NEWLINE
  ( 
    ((SPACE)*
      ('+'
      { 
        $type = ORDEREDLIST ; 
      }
      | ('-')+
      {
        String fragment = $text.replaceAll("\\s", "") ;
        if(fragment.length() == 1)
          $type = UNORDEREDLIST ;        
        else if (fragment.length() < 2)
          $type = STRIKESYMBOL ;
        else if(fragment.length() < 20)
          $type = PUNCTUATIONMARK ;
        else
          $type = SEPARATOR ;
      } 
      | ':'
      {
        $type = DEFINITIONLIST ;
      }
      | SPACE ()
      {
        $type = NEWLINE ;
      })
    )
    | '%'
    {
      $type = COMMENT ;      
    }
    | (TAB)+
    {
      $type = QUOTE ;
    }
    | '```' 
    {
      $type = VERBATIMLINE ;
    }
    | ()
    {
      $type = NEWLINE ; 
    }
  );
  
fragment NEWLINE :
  ( '\r\n'
  | '\n' 
  ) ;

fragment LETTER :
  'a'..'z'  | 'A'..'Z';
  
fragment DIGIT :
  '0'..'9' ;
    
WHITESPACE :
    SPACE
    | TAB
    | '\f' ; 

fragment SPACE :
  ' ' ;

fragment TAB :
  '\t' ;
  
fragment COMMENT : 
  NEWLINE '%' ;
  
fragment ORDEREDLIST : 
  NEWLINE (SPACE)* '+' ;

fragment UNORDEREDLIST : 
  NEWLINE (SPACE)* '-';
  
fragment DEFINITIONLIST : 
  NEWLINE (SPACE)* ':' ;

fragment QUOTE :
  NEWLINE (TAB)+ ;

fragment VERBATIMLINE :
  NEWLINE '```' ;  

fragment VERBATIMAREA :
  ('`')+;
  
fragment MONOSPACESYDMBOL :
  ('`')+; 